微服务技术的历程和展望 微服务发展的历程 从最初的单体架构到如今的云原生、服务网格,微服务经历了长达十余年的演进。它是技术发展、组织架构变革以及云计算普及共同催生的产物。下面我们来回顾一下微服务技术发展历程中的四个主要阶段。
微服务技术的发展趋势 更多微服务演进趋势,推荐参考:
链路追踪工具的横向对比 好,回到本文正题,聚焦链路追踪工具。我归纳了几个当前链路追踪工具的几个扛把子,对比如下:
技术的选型:
如果你的核心体系是 Java / Spring Cloud (如你的 Pro-Cloud 体系):直接闭眼选 SkyWalking。它的零代码侵入能让你在半小时内把探针挂载到 Gateway、User、Order 以及各大中间件(Redis/MQ)上,且功能极其全面,是国内微服务生态的绝对霸主。
如果你需要监控方法级、甚至是某一行代码的执行耗时:可以考虑 Pinpoint,它的调用树细致到了方法栈级别,但注意准备好足够的存储资源(HBase)。
如果你的微服务是多语言混编(Java + Go + Python),且瞄准了云原生 Service Mesh 架构:长远来看一定要布局 OpenTelemetry。它正在终结全行业的链路追踪标准,各大厂商(包括 SkyWalking 最新版)都在全面兼容它的协议。
Skywalking 的原理 在正式切入 SkyWalking 的源码和实战之前,必须要先吃透它的地基——探针(Agent)和代理(Proxy)。
代理技术及其缺陷 在 Java 生态中,代理模式的核心思想是 为一个已知对象提供一个替身(代理对象),由替身来控制对原对象的访问,并在访问前后悄悄加入一些额外操作 (如打印日志、开启事务、Sentinel 限流等)。分布式链路追踪需要捕获微服务之间的每一次方法调用。Java 中的代理技术主要分为两大类:
JDK 动态代理:要求目标类必须实现接口。它利用 java.lang.reflect.Proxy 在内存中动态生成一个接口的实现类。
CGLIB 动态代理:通过继承目标类,利用字节码技术(ASM)在运行时动态生成一个目标类的子类。Spring AOP 默认就采用了这种机制。
动态代理是代码层面的技术。如果想给项目里成百上千个类加上代理,必须显式编写 Spring AOP 配置,或者手动用 Proxy.newProxyInstance 去包一层。对于分布式组件(如捕获远程 Redis、MySQL 驱动的内部调用),代码侵入性极大。
探针技术的原理 如果说动态代理是在应用代码内部做手脚,那么探针技术(JavaAgent)则是直接站在 JVM 虚拟机的高度,在类加载阶段进行 “降维打击”。JavaAgent 是 Java 1.5 引入的技术。它本质上是一个独立于业务系统的外挂 Jar 包。 利用 JVM 提供的 Instrumentation 接口,JavaAgent 可以在业务类的字节码(.class 文件)被 JVM 加载到内存之前,强行拦截并肆意修改其内容。
探针的核心工作原理就是 字节码注入 ,当微服务启动时,JVM 类加载器准备加载一个类(例如 Spring Boot 的 UserController.class):
$$\text{UserController.class(磁盘)} \xrightarrow{\text{JVM加载}} \mathbf{[JavaAgent 拦截器]} \xrightarrow{\text{魔改/注入代理代码}} \text{魔改后的字节码(内存)}$$
探针技术在类加载阶段,直接通过修改操作码,在原方法体的前后硬编码塞入统计耗时、记录链路 ID 的逻辑。
JavaAgent 的两大核心入口点:
premain(静态加载,最常用):在项目的 main 方法执行之前触发。SkyWalking 挂载探针使用的就是这种模式(启动参数加 -javaagent:/path/to/skywalking-agent.jar)。
agentmain(动态热挂载):在项目运行过程中,利用虚拟机动态工具(Attach API)在不重启服务的情况下,强行把探针注入到正在运行的 JVM 进程中。
Skywalking 的底层实现 直接去改类的二级制字节码(操作字节码指令集,如 aload_0, invokevirtual)极其痛苦且容易出错。早期框架如 Pinpoint 使用了较为底层的 ASM 或 Javassist。而 SkyWalking 的内核则采用了目前业内最优雅、性能最好的高级字节码框架——Byte Buddy。Byte Buddy 封装了复杂的 JVM 指令,允许开发者用纯粹的 Java 流式代码(Fluent API)来改写字节码。例如,SkyWalking 内部要拦截并魔改一个方法,其核心伪代码极其优雅:
1 2 3 4 5 6 7 new AgentBuilder .Default() .type(ElementMatchers.named("com.koohub.user.service.UserService" )) .transform((builder, typeDescription, classLoader, module ) -> builder.method(ElementMatchers.named("getUserInfo" )) .intercept(MethodDelegation.to(MyInterceptor.class)) ).installOn(instrumentation);
Skywalking 的安装部署 官网 、下载 、GitHub 、官方文档 、中文文档 。
使用 docker 安装部署 我们在此使用 9.6.0 作为安装版本,使用 Docker-Compose 启动后端的核心大本营(OAP Server + WebUI),数据存储采用最轻量、适合开发联调的内置内存/H2 模式(生产环境可一键切换为 Elasticsearch 或官方自研的 BanyanDB)。由于 docker 比较轻量,我经常使用这种方式安装单机版的 skywalking,追踪和调试本地开发环境,非常 nice。
第一步,扫除之前的安装垃圾:
1 2 3 4 5 docker compose down -v docker rmi apache/skywalking-oap-server:9.6.0 apache/skywalking-ui:9.6.0
第二步:编写全新、干净的 docker-compose.yml
注意,如果之后修改了 docker-compose.yml,执行 docker compose up -d skywalking-oap 重启容器之后,因为使用的是 H2 内存数据库,刚才的临时指标会清空,需要再跑几笔 curl 重新喂一下数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 version: '3.8' services: skywalking-oap: image: apache/skywalking-oap-server:9.6.0 container_name: skywalking-oap restart: always ports: - "11800:11800" - "12800:12800" environment: SW_STORAGE: h2 TZ: Asia/Shanghai SW_ENABLE_UPDATE_UI_TEMPLATE: "true" skywalking-ui: image: apache/skywalking-ui:9.6.0 container_name: skywalking-ui restart: always ports: - "8686:8080" environment: SW_OAP_ADDRESS: http://skywalking-oap:12800 TZ: Asia/Shanghai depends_on: - skywalking-oap
第三步:一键启动 9.6.0 后端,在当前 docker-compose.yml 目录下执行:
启动完成后,你可以直接在浏览器打开: localhost:8686 就可以看到 9.6.0 版本的干净大屏。
被追踪的应用挂载探针 第一步:先去官网下载对应版本的探针 agent。下载页面
1 2 3 4 5 6 7 8 $ wget https://dlcdn.apache.org/skywalking/java-agent/9.6.0/apache-skywalking-java-agent-9.6.0-src.tgz $ tar -xzvf apache-skywalking-java-agent-9.6.0-src.tgz -C . $ ls LICENSE bootstrap-plugins licenses optional-reporter-plugins NOTICE config logs plugins activations expired-plugins optional-plugins skywalking-agent.jar
第二步:由于我们的被追踪应用包含 spring cloud gateway 这种底层是 netty + webflux 的组件,所以我们还需要将 optional-plugins 目录中的三个 jar 包(根据你实际的版本)拷贝到 plugins 目录(都是泪啊同志们😭)。
1 2 3 $ cp optional-plugins/apm-spring-cloud-gateway-4.x-plugin-9.6.0.jar plugins/ $ cp optional-plugins/apm-spring-webflux-6.x-plugin-9.6.0.jar plugins/ $ cp optional-plugins/apm-netty-http-4.1.x-plugin-9.6.0.jar plugins/
第三步:被追踪应用的启动。被追踪应用集群的构建请参考 《Spring Cloud Gateway - 使用测试案例》 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 -javaagent:/xxx/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=zdemo-gateway -Dskywalking.collector.backend_service=127.0.0.1:11800 -Djava.net.preferIPv4Stack=true -javaagent:/xxx/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=zdemo-scloud-order -Dskywalking.collector.backend_service=127.0.0.1:11800 -Djava.net.preferIPv4Stack=true -javaagent:/xxx/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=zdemo-scloud-user -Dskywalking.collector.backend_service=127.0.0.1:11800 -Djava.net.preferIPv4Stack=true
完成以上三步,从网关作为入口发几个请求:
1 2 3 4 5 $ curl -H "Authorization: my-jwt-token-xxx" http://192.168.1.5:8880/user-serv/feign/user/order?orderNo=1 $ curl -H "Authorization: my-jwt-token-xxx" http://192.168.1.5:8880/user-serv/dubbo/user/order?orderNo=2
这时候再次访问 Skywalking 网页端,在服务项中就可以观察到请求数据和集群的链路拓扑图了。✌🏻
Skywalking 探针整合 logback 建议直接参考官方文档:Skywalking Logback 工具包官方配置文档(GitHub 源码站) 。
在生产环境中,把 SkyWalking 的 tid 注入到应用日志(如 Logback)中,是实现 “指标、链路、日志三合一” 的最核心步骤。通过它,你不需要编写任何拦截器或手动往 MDC 里塞 traceId 或者移除 traceId,探针会自动通过字节码技术把 traceId 悄悄塞进你的日志框架中。而且如果你的 Spring 项目中开启了异步线程池(如线程池复用),你只需要在配置中额外追加一个 SkyWalking 的线程池装饰器(如 RunnableWrapper.of(runnable)),探针就会跨线程把这个 TID 自动复制到子线程的 Logback 框架中,彻底解放双手!
实现日志打印全局 traceId 第一步 :给应用引入依赖包(版本请根据实际的 skywalking 探针版本):
1 2 3 4 5 <dependency > <groupId > org.apache.skywalking</groupId > <artifactId > apm-toolkit-logback-1.x</artifactId > <version > 9.6.0</version > </dependency >
第二步 :日志配置文件的更改,编辑 logback-spring.xml(关键是 TraceIdPatternLogbackLayout 和 %tid)。
示例一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="UTF-8" ?> <configuration > <appender name ="STDOUT" class ="ch.qos.logback.core.ConsoleAppender" > <encoder class ="ch.qos.logback.core.encoder.LayoutWrappingEncoder" > <layout class ="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout" > <pattern > %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%tid] %logger{36} - %msg%n</pattern > </layout > <charset > UTF-8</charset > </encoder > </appender > <root level ="INFO" > <appender-ref ref ="STDOUT" /> </root > </configuration >
示例二
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 <?xml version="1.0" encoding="UTF-8" ?> <configuration scan ="true" scanPeriod ="60 seconds" > <property name ="LOG_PATH" value ="./logs" /> <property name ="APP_NAME" value ="order" /> <property name ="CONSOLE_LOG_PATTERN" value ="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level ${PID:- } --- [%15.15thread] [%tid] %-40.40logger{39} : %m%n" /> <property name ="FILE_LOG_PATTERN" value ="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level ${PID:- } --- [%thread] [%tid] %logger{50} - [%method,%line] - %m%n" /> <appender name ="CONSOLE" class ="ch.qos.logback.core.ConsoleAppender" > <encoder class ="ch.qos.logback.core.encoder.LayoutWrappingEncoder" > <layout class ="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout" > <pattern > ${CONSOLE_LOG_PATTERN}</pattern > </layout > <charset > UTF-8</charset > </encoder > </appender > <appender name ="INFO_FILE" class ="ch.qos.logback.core.rolling.RollingFileAppender" > <file > ${LOG_PATH}/${APP_NAME}-sys-info.log</file > <rollingPolicy class ="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" > <fileNamePattern > ${LOG_PATH}/archive/${APP_NAME}-sys-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern > <maxFileSize > 100MB</maxFileSize > <maxHistory > 30</maxHistory > <totalSizeCap > 30GB</totalSizeCap > </rollingPolicy > <encoder class ="ch.qos.logback.core.encoder.LayoutWrappingEncoder" > <layout class ="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout" > <pattern > ${FILE_LOG_PATTERN}</pattern > </layout > <charset > UTF-8</charset > </encoder > <filter class ="ch.qos.logback.classic.filter.LevelFilter" > <level > ERROR</level > <onMatch > DENY</onMatch > <onMismatch > ACCEPT</onMismatch > </filter > </appender > <appender name ="ERROR_FILE" class ="ch.qos.logback.core.rolling.RollingFileAppender" > <file > ${LOG_PATH}/${APP_NAME}-sys-error.log</file > <rollingPolicy class ="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" > <fileNamePattern > ${LOG_PATH}/archive/${APP_NAME}-sys-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern > <maxFileSize > 100MB</maxFileSize > <maxHistory > 60</maxHistory > </rollingPolicy > <encoder class ="ch.qos.logback.core.encoder.LayoutWrappingEncoder" > <layout class ="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout" > <pattern > ${FILE_LOG_PATTERN}</pattern > </layout > <charset > UTF-8</charset > </encoder > <filter class ="ch.qos.logback.classic.filter.ThresholdFilter" > <level > ERROR</level > </filter > </appender > <root level ="INFO" > <appender-ref ref ="CONSOLE" /> <appender-ref ref ="INFO_FILE" /> <appender-ref ref ="ERROR_FILE" /> </root > </configuration >
第三步 :携带探针重新启动相关的应用。这时候就可以观察到:
1 2 3 4 5 6 7 8 9 10 11 2026-06-23 03:19:39.703 [http-nio-8180-exec-10] INFO [TID:f7b0b115a22544d28461d875834dffed.160.17821559796900683] z.s.user.controller.UserController - 使用 dubbo 发起 RPC 请求,订单号: 1111 2026-06-23 03:19:39.730 INFO 75998 --- [:20881-thread-5] [TID:f7b0b115a22544d28461d875834dffed.160.17821559796900683] z.scloud.order.service.OrderServiceImpl : 收到 RPC 请求,订单号: 1111 2026-06-23 03:12:20.234 [http-nio-8180-exec-3] ERROR [TID:f7b0b115a22544d28461d875834dffed.155.17821555361440483] o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.apache.dubbo.rpc.RpcException: java.util.concurrent.ExecutionException: org.apache.dubbo.rpc.StatusRpcException: DEADLINE_EXCEEDED : Waiting server-side response timeout by scan timer. start time : 2026-06-23 03:12:16.867, end time : 2026-06-23 03:12:19.949, timeout : 3000 ms, service: zdemo.scloud.api.service.dubbo.OrderService, method: getOrderDetails] with root cause org.apache.dubbo.rpc.StatusRpcException: DEADLINE_EXCEEDED : Waiting server-side response timeout by scan timer. start time : 2026-06-23 03:12:16.867, end time : 2026-06-23 03:12:19.949, timeout : 3000 ms, service: zdemo.scloud.api.service.dubbo.OrderService, method: getOrderDetails at org.apache.dubbo.rpc.TriRpcStatus.asException(TriRpcStatus.java:213) at org.apache.dubbo.rpc.protocol.tri.DeadlineFuture$TimeoutCheckTask .notifyTimeout(DeadlineFuture.java:162) ...
异常的情况,就可以直接复制 tid 到 skywaking dashboard 查询对应的全局链路了。
需要注意的地方 你之前如果编写了 TraceIdMdcFilter 去维护 MDC,但在复杂的微服务异步调用(比如:你代码里用了 @Async 异步线程池、或者编程式线程拉起、或者使用 WebFlux 响应式框架)中,手动维护的 MDC 会因为线程切换直接发生断裂,导致下游线程日志里抓不到 ID,甚至由于未 remove 清理造成线程池相互污染。所以在实际的生产环境中,请彻底移除 MDC 的逻辑,全面拥抱 skywaking!
日志要不要灌到 skywalking 在实际生产架构中,绝大多数企业不会将 SkyWalking 作为应用日志的核心存储和查询中心,而是依然选择直接打到 ES或专门的日志系统。
为了既不冲垮 SkyWalking,又能享受“看图点进日志”的丝滑体验,最成熟的做法是:链路走 SkyWalking,日志走 ES,二者通过 TraceId 强强联合 。架构拓扑:
链路数据 :应用挂载 SkyWalking Agent $\rightarrow$ 直接上报给 SkyWalking OAP $\rightarrow$ 存入 APM 专用的 ES/BanyanDB(只保留 3 天)。
全量日志 :应用控制台打印日志(带有 TraceId) $\rightarrow$ Filebeat/Logstash 异步采集 $\rightarrow$ 经过 Kafka 削峰 $\rightarrow$ 存入独立的日志 ES 集群(保留 30 天以上)。
总结来说,把全量业务日志打给 SkyWalking 是 “小材大用”,还会把监控拖垮;让它专注做链路追踪,日志交给 ES,通过 TraceId 做桥梁,才是生产标配。
日志灌入 ES 的标准做法 把日志灌入 ES(Elasticsearch)通常有两种完全不同的架构路线:
一种是轻量侵入式,直接通过 SkyWalking Logback GRPC Appender 上报,只适合处理小规模日志;
另一种是生产标准级异步解耦 Filebeat/Logstash + ES 上报,是大规模日志处理的标准做法。
不太好的方案 虽然不推荐第一种做法,但这里还是做一个介绍,实现该方案总共三步走:
引入 GRPC 日志上报依赖
1 2 3 4 5 <dependency > <groupId > org.apache.skywalking</groupId > <artifactId > apm-toolkit-logback-1.x</artifactId > <version > 9.6.0</version > </dependency >
在 logback-spring.xml 中追加 GRPC Appender
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <appender name ="SKYWALKING_GRPC" class ="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender" > <encoder class ="ch.qos.logback.core.encoder.LayoutWrappingEncoder" > <layout class ="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout" > <pattern > ${FILE_LOG_PATTERN}</pattern > </layout > </encoder > </appender > <root level ="INFO" > <appender-ref ref ="CONSOLE" /> <appender-ref ref ="INFO_FILE" /> <appender-ref ref ="ERROR_FILE" /> <appender-ref ref ="SKYWALKING_GRPC" /> </root >
在 SkyWalking 中开启 ES 存储
1 2 3 4 5 storage: selector: ${SW_STORAGE:elasticsearch} elasticsearch: namespace: ${SW_STORAGE_ES_NAMESPACE:""} clusterNodes: ${SW_STORAGE_ES_CLUSTER_NODES:127.0.0.1:9200}
最终效果:服务启动后,日志会随 GRPC 协议发送给 OAP 写入 ES。你在 SkyWalking 的 UI 界面上,点击某条分布式链路,就能直接在右侧看到和该 TraceId 绑定的高亮业务日志,实现真正的“链路-日志一体化。
更推荐的方案 如果微服务并发极高,直接用方案一的 skywalking GRPC 上报会占用微服务的 JVM 内存和网络带宽,产生性能抖动。还是强烈推荐第二种方案,采用 异步落地本地磁盘 $\rightarrow$ 采集器异步监听 $\rightarrow$ 灌入 ES 的解耦架构。
配置 Filebeat 采集器 :在服务器上部署 Filebeat,修改 filebeat.yml 收集你的日志:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 filebeat.inputs: - type: log enabled: true paths: - /path/to/logs/order-sys-*.log multiline.type: pattern multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}' multiline.negate: true multiline.match: after output.elasticsearch: hosts: ["http://127.0.0.1:9200" ] index: "order-service-log-%{+yyyy.MM.dd} "
在 Kibana 中根据 TraceId 检索 。当 Filebeat 把日志灌入 ES 后,你可以直接在 Kibana 或者是现有的日志数据大屏中:
创建名为 “order-service-log-*” 的索引模式。
遇到线上故障时,直接在 Kibana 搜索框中输入你在前面日志里看到的 tid。
此时整个分布式系统中所有流经服务的、包含此 ID的业务日志、报错信息、上下文,都将被检索出来。
让 skywalking 支持告警 关于这部分功能的实现,也可以直接参考官方文档 Skywalking Alerting 说明。
配置 OAP 告警规则 SkyWalking 的所有告警规则都定义在后端 OAP 容器内的 config/alarm-settings.yml 文件中。对这个配置文件进行修改,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 rules: service_resp_time_rule: expression: sum(service_resp_time > 1000 ) >= 3 period: 10 silence-period: 5 message: 【SkyWalking告警】服务 {name } 响应时间过长,最近 10 分钟内已连续 3 次超时! service_sla_rule: expression: sum(service_sla < 8000 ) >= 2 period: 10 silence-period: 3 message: 【SkyWalking告警】服务 {name } 成功率太低,最近 10 分钟内已有 2 次跌破 80 %! service_resp_time_percentile_rule: expression: sum(service_percentile{_='0,1,2,3,4'} > 1000 ) >= 3 period: 10 silence-period: 5 message: Percentile response time of service {name } alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000 , p75 > 1000 , p90 > 1000 , p95 > 1000 , p99 > 1000 service_instance_resp_time_rule: expression: sum(service_instance_resp_time > 1000 ) >= 2 period: 10 silence-period: 5 message: Response time of service instance {name } is more than 1000ms in 2 minutes of last 10 minutes database_access_resp_time_rule: expression: sum(database_access_resp_time > 1000 ) >= 2 period: 10 message: Response time of database access {name } is more than 1000ms in 2 minutes of last 10 minutes endpoint_relation_resp_time_rule: expression: sum(endpoint_relation_resp_time > 1000 ) >= 2 period: 10 message: Response time of endpoint relation {name } is more than 1000ms in 2 minutes of last 10 minutes hooks: webhook: default: is-default: true urls: - http://192.168.1.5:8081/sys/alarm/receive
你可以直接将容器内的配置文件拉取到本地宿主机,然后在宿主机改完配置文件,再塞到容器中。
1 2 3 4 5 6 7 8 9 10 11 $ docker cp skywalking-oap:/skywalking/config/alarm-settings.yml ./alarm-settings.yml $ vim alarm-settings.yml $ docker cp ./alarm-settings.yml skywalking-oap:/skywalking/config/alarm-settings.yml $ docker compose restart skywalking-oap
或者直接进入到容器内部进行修改:
1 2 3 4 5 6 7 8 9 10 $ docker exec -it skywalking-oap bash apt-get update apt-get install -y vim vim alarm-settings.yml
编写告警接收接口 上面我们在 config/alarm-settings.yml 配置了 hooks.webhook.default.urls,那我们就来实现这个告警接收器。根据 SkyWalking 9.x 的官方标准规范,告警数据的 JSON 结构映射如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package zdemo.scloud.order.dto;import com.fasterxml.jackson.databind.JsonNode;import lombok.Data;@Data public class SkyWalkingAlarmDTO { private int scopeId; private String scope; private String name; private String id0; private String id1; private String ruleName; private String alarmMessage; private long startTime; private JsonNode tags; }
编写 Webhook 接收接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package zdemo.scloud.order.controller;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import zdemo.scloud.order.dto.SkyWalkingAlarmDTO;import java.util.List;@Slf4j @RestController @RequestMapping("/sys/alarm") public class AlarmController { @PostMapping("/receive") public void receiveAlarm (@RequestBody List<SkyWalkingAlarmDTO> alarmList) { if (alarmList == null || alarmList.isEmpty()) { return ; } for (SkyWalkingAlarmDTO alarm : alarmList) { log.error("【SkyWalking 系统告警】触发规则: {}, 目标服务: {}, 告警内容: {}, 标签数据: {}" , alarm.getRuleName(), alarm.getName(), alarm.getAlarmMessage(), alarm.getTags() != null ? alarm.getTags().toString() : "{}" ); } } }
测试验证 在我们的 OrderController 里故意写一段延迟,或者直接把目标依赖服务强行断网/下线:
1 2 3 4 5 6 7 8 9 10 @GetMapping("/details") public OrderDTO getUserOrderDetails (@RequestParam String orderNo) { log.info("收到客户端订单:{}" , orderNo); try { Thread.sleep(1500 ); } catch (InterruptedException e) { e.printStackTrace(); } return new OrderDTO (orderNo, new BigDecimal ("200.00" ), "Owlias教程:" + port); }
使用循环命令连续请求该慢接口 至少 1~2 分钟,确保满足配置中的 count: 3(连续多次超时)以及 period 的时间滑窗要求:
1 for i in {1..100}; do curl -H "Authorization: my-jwt-token-xxx" http://192.168.1.5:8880/user-serv/feign/user/order?orderNo=1; sleep 0.1; done
这时候来到 SkyWalking 的前端大盘,查看告警页,就会看到告警记录已经显示出来了。并且在应用端接收器也可以收到告警消息:
1 2 3 4 5 6 7 8 9 10 11 2026-02-13 22:04:25.078 ERROR 92973 --- [nio-8081-exec-7] [TID:26eb1323cd5343af8229b5ba067e4863.96.17821910649510009] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: endpoint_relation_resp_time_rule, 目标服务: User in User to Netty-http:/user-serv/feign/user/order?orderNo=1111 in zdemo-gateway, 告警内容: Response time of endpoint relation User in User to Netty-http:/user-serv/feign/user/order?orderNo=1111 in zdemo-gateway is more than 1000ms in 2 minutes of last 10 minutes, 标签数据: [] 2026-02-13 22:04:25.081 ERROR 92973 --- [nio-8081-exec-7] [TID:26eb1323cd5343af8229b5ba067e4863.96.17821910649510009] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_instance_resp_time_rule, 目标服务: 3397cd08f9de45c5b91e95bd3f280986@192.168.64.1 of zdemo-scloud-user, 告警内容: Response time of service instance 3397cd08f9de45c5b91e95bd3f280986@192.168.64.1 of zdemo-scloud-user is more than 1000ms in 2 minutes of last 10 minutes, 标签数据: [] 2026-02-13 22:04:25.082 ERROR 92973 --- [nio-8081-exec-7] [TID:26eb1323cd5343af8229b5ba067e4863.96.17821910649510009] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_instance_resp_time_rule, 目标服务: dc4f04eb2082451eaa627b572926971b@192.168.64.1 of zdemo-scloud-order, 告警内容: Response time of service instance dc4f04eb2082451eaa627b572926971b@192.168.64.1 of zdemo-scloud-order is more than 1000ms in 2 minutes of last 10 minutes, 标签数据: [] 2026-02-13 22:04:25.082 ERROR 92973 --- [nio-8081-exec-7] [TID:26eb1323cd5343af8229b5ba067e4863.96.17821910649510009] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_instance_resp_time_rule, 目标服务: 532846803edc44cab8ef72b10ab61c33@192.168.64.1 of zdemo-gateway, 告警内容: Response time of service instance 532846803edc44cab8ef72b10ab61c33@192.168.64.1 of zdemo-gateway is more than 1000ms in 2 minutes of last 10 minutes, 标签数据: [] 2026-02-13 22:04:25.083 ERROR 92973 --- [nio-8081-exec-7] [TID:26eb1323cd5343af8229b5ba067e4863.96.17821910649510009] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_instance_resp_time_rule, 目标服务: cd75011f711847fbb0566bb1127b738a@192.168.64.1 of zdemo-scloud-order, 告警内容: Response time of service instance cd75011f711847fbb0566bb1127b738a@192.168.64.1 of zdemo-scloud-order is more than 1000ms in 2 minutes of last 10 minutes, 标签数据: [] 2026-02-13 22:05:24.916 ERROR 92973 --- [nio-8081-exec-9] [TID:26eb1323cd5343af8229b5ba067e4863.98.17821911249140011] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_resp_time_rule, 目标服务: zdemo-scloud-user, 告警内容: 【SkyWalking告警】服务 zdemo-scloud-user 响应时间过长,最近 10 分钟内已连续 3 次超时!, 标签数据: [] 2026-02-13 22:05:24.916 ERROR 92973 --- [nio-8081-exec-9] [TID:26eb1323cd5343af8229b5ba067e4863.98.17821911249140011] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_resp_time_rule, 目标服务: zdemo-scloud-order, 告警内容: 【SkyWalking告警】服务 zdemo-scloud-order 响应时间过长,最近 10 分钟内已连续 3 次超时!, 标签数据: [] 2026-02-13 22:05:24.917 ERROR 92973 --- [nio-8081-exec-9] [TID:26eb1323cd5343af8229b5ba067e4863.98.17821911249140011] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_resp_time_rule, 目标服务: zdemo-gateway, 告警内容: 【SkyWalking告警】服务 zdemo-gateway 响应时间过长,最近 10 分钟内已连续 3 次超时!, 标签数据: [] 2026-02-13 22:05:24.917 ERROR 92973 --- [nio-8081-exec-9] [TID:26eb1323cd5343af8229b5ba067e4863.98.17821911249140011] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_resp_time_percentile_rule, 目标服务: zdemo-scloud-user, 告警内容: Percentile response time of service zdemo-scloud-user alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000, 标签数据: [] 2026-02-13 22:05:24.917 ERROR 92973 --- [nio-8081-exec-9] [TID:26eb1323cd5343af8229b5ba067e4863.98.17821911249140011] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_resp_time_percentile_rule, 目标服务: zdemo-scloud-order, 告警内容: Percentile response time of service zdemo-scloud-order alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000, 标签数据: [] 2026-02-13 22:05:24.917 ERROR 92973 --- [nio-8081-exec-9] [TID:26eb1323cd5343af8229b5ba067e4863.98.17821911249140011] z.s.order.controller.AlarmController : 【SkyWalking 系统告警】触发规则: service_resp_time_percentile_rule, 目标服务: zdemo-gateway, 告警内容: Percentile response time of service zdemo-gateway alarm in 3 minutes of last 10 minutes, due to more than one condition of p50 > 1000, p75 > 1000, p90 > 1000, p95 > 1000, p99 > 1000, 标签数据: []
标题:
Spring Cloud 微服务系列 - 微服务的链路追踪工具 - skywalking